package com.zuo_book.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.zuo_book.service.FileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 文件服务实现类 - 阿里云OSS版
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class FileServiceImpl implements FileService {

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    @Value("${aliyun.oss.urlPrefix}")
    private String urlPrefix;

    @Override
    public String uploadFile(MultipartFile file, String directory) throws IOException {
        if (file == null || file.isEmpty()) {
            log.error("上传文件失败：文件为空");
            throw new IOException("文件不能为空");
        }

        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            log.error("上传文件失败：文件名为空");
            throw new IOException("文件名不能为空");
        }

        log.info("开始上传文件: {}, 大小: {}, 内容类型: {}", originalFilename, file.getSize(), file.getContentType());
        
        // 输出所有OSS配置，帮助调试
        log.info("OSS配置: endpoint={}, accessKeyId={}, bucketName={}, urlPrefix={}", 
            endpoint,
            accessKeyId != null ? accessKeyId.substring(0, 4) + "..." : "null",
            bucketName,
            urlPrefix);

        // 验证OSS配置
        if (endpoint == null || accessKeyId == null || accessKeySecret == null || bucketName == null) {
            log.error("阿里云OSS配置错误, endpoint={}, accessKeyId={}, bucketName={}", 
                    endpoint != null ? "已配置" : "未配置",
                    accessKeyId != null ? "已配置" : "未配置",
                    bucketName != null ? "已配置" : "未配置");
            throw new IOException("OSS配置错误，请检查配置文件");
        }

        try {
            // 获取文件后缀
            String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            
            // 生成新文件名
            String newFilename = UUID.randomUUID().toString().replace("-", "") + suffix;
            
            // 按日期生成目录
            String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            
            // 构建OSS文件存储路径
            String ossPath = directory + "/" + datePath + "/" + newFilename;
            
            log.info("准备上传文件到OSS, 路径: {}", ossPath);
            
            // 创建OSSClient实例
            OSS ossClient = null;
            try {
                ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
                
                // 检查OSS客户端
                if (ossClient == null) {
                    log.error("创建OSS客户端失败");
                    throw new IOException("创建OSS客户端失败");
                }
                
                // 检查bucket是否存在
                boolean bucketExists = ossClient.doesBucketExist(bucketName);
                if (!bucketExists) {
                    log.error("Bucket不存在: {}", bucketName);
                    throw new IOException("OSS Bucket不存在: " + bucketName);
                }
                
                // 创建上传Object的元数据
                ObjectMetadata metadata = new ObjectMetadata();
                // 设置ContentType
                metadata.setContentType(file.getContentType());
                metadata.setContentLength(file.getSize());
                
                log.info("开始上传文件到OSS...");
                
                // 上传文件
                ossClient.putObject(bucketName, ossPath, file.getInputStream(), metadata);
                
                log.info("文件上传成功");
                
                // 返回文件访问URL
                String fullUrl = urlPrefix + ossPath;
                log.info("文件访问URL: {}", fullUrl);
                
                // 测试文件是否可以访问
                try {
                    boolean objectExists = ossClient.doesObjectExist(bucketName, ossPath);
                    log.info("验证文件是否存在: {}", objectExists ? "存在" : "不存在");
                } catch (Exception e) {
                    log.warn("验证文件存在时出现异常", e);
                }
                
                return fullUrl;
            } catch (Exception e) {
                log.error("上传文件到OSS失败: {}", e.getMessage(), e);
                throw new IOException("上传文件失败: " + e.getMessage());
            } finally {
                // 关闭OSSClient
                if (ossClient != null) {
                    try {
                        ossClient.shutdown();
                        log.info("OSS客户端已关闭");
                    } catch (Exception e) {
                        log.warn("关闭OSS客户端时发生异常", e);
                    }
                }
            }
        } catch (Exception e) {
            log.error("文件处理过程出现异常", e);
            throw new IOException("文件处理失败: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteFile(String fileUrl) {
        if (fileUrl == null || fileUrl.isEmpty()) {
            return false;
        }
        
        // 如果不是OSS URL，直接返回
        if (!fileUrl.startsWith(urlPrefix)) {
            return false;
        }
        
        // 从URL中提取文件路径
        String ossPath = fileUrl.substring(urlPrefix.length());
        
        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        
        try {
            // 删除文件
            ossClient.deleteObject(bucketName, ossPath);
            return true;
        } catch (Exception e) {
            log.error("从OSS删除文件失败", e);
            return false;
        } finally {
            // 关闭OSSClient
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
} 